package com.oros.db;

import com.vaadin.data.Container.Filter;
import java.util.*;
public class AEViewDefinition extends AETableDefinition {
	/**
	 * 
	 */
	private static final long serialVersionUID = -5081351804064194776L;
	public int containerNo,sourceNo,columnAmount;
	public int[] columnAmounts;
	public boolean hasGeneratedColumns;
	public AETableContainer[] tables;
	public int[] joinColumns;
	public int[] leftOuterJoin;
	public Filter[] whereFilters;
	public String[] sortColumns;
	public boolean[] ascending;
    public boolean[] readOnlyTables;
	public AEGroupInfo[] groupBy;
    public AEViewDefinition(String viewName,AETableContainer[] tables,boolean[] readOnlyTables,String[] joinLeftTableFields,
    		int[] leftOuterJoin,Filter[] whereFilters,String[] sortColumns,boolean[] ascending,
    		LinkedHashMap<String,String> ColumnNameAliases,AEGeneratedColumn[] generatedColumns,
    		AEGroupInfo[] groupBy)
           throws Exception 
    {
    	super();
    	if (tables==null || tables.length==0) throw new Exception("Tables cannot be null or emtpy in view container");
    	containerNo = tables.length;
    	if (readOnlyTables==null)
    	{
    		readOnlyTables=new boolean[containerNo];
    		for(int i=0;i<containerNo;i++) readOnlyTables[i]=true;
    	}
    	if (readOnlyTables.length!=containerNo)
    		throw new Exception("AEViewContainer "+viewName+" readOnlyTables parameter must have the same dimension as in tables");
        this.readOnlyTables = readOnlyTables;
    	if (containerNo>1 && (joinLeftTableFields==null || joinLeftTableFields.length!=containerNo-1))
        	throw new Exception("joinLeftTableFields parameter dimension must be the table number minus 1"); 
        if (leftOuterJoin!=null)
        {
        	if (leftOuterJoin.length!=containerNo-1)
        		throw new Exception("leftOuterJoin parameter must be either null (assuming inner join always) or with the dimension equal to the table number minus 1");
        }
        else 
        {
        	leftOuterJoin = new int[containerNo-1];
        	for(int i=0;i<containerNo-1;i++) leftOuterJoin[i]=0;
        			
        }
        if (groupBy!=null) throw new Exception("Sorry, groupBy is not supported yet! Wait for new releases");
        this.tables = tables;
        this.leftOuterJoin = leftOuterJoin;
        this.whereFilters = whereFilters;
        this.sortColumns = sortColumns;
        this.ascending = ascending;
        this.groupBy = groupBy;
        hasGeneratedColumns = generatedColumns!=null && generatedColumns.length>0;
        sourceNo=containerNo;
        if (hasGeneratedColumns) sourceNo++;
        columnAmounts=new int[sourceNo];
        columnAmount=0;
        for(int i=0;i<containerNo;i++)
        {
        	int k=tables[i].columnAmount;
        	columnAmounts[i] = k;
        	columnAmount+=k;
        }
        if (hasGeneratedColumns)
        {
        	int k= generatedColumns.length;
        	columnAmounts[sourceNo-1]=k;
        	columnAmount+=k;
        }
        this.tableName = viewName;
        this.columnDefaults = new Object[columnAmount];
        this.columnNames = new String[columnAmount];
        this.columnTypes = new Class<?>[columnAmount];
        this.joinColumns = new int[containerNo-1];
        int basis = 0;
        if (containerNo==1)
        {
        	String[] colNames=tables[0].columnNames;
        	Object[] objDefs = tables[0].columnDefaults;
        	Class<?>[] types = tables[0].columnTypes;
        	this.primaryKeyColumn = colNames[tables[0].idColumn];
        	String str = (ColumnNameAliases==null)?null:ColumnNameAliases.get(this.primaryKeyColumn);
            if (str!=null) this.primaryKeyColumn = str;
        	int n=columnAmounts[0];
        	for(int i=0;i<n;i++)
        	{
        		str = colNames[i];
        		String snew = (ColumnNameAliases==null)?str:ColumnNameAliases.get(str);
        		columnNames[i]=snew==null?str:snew;
        		columnDefaults[i]=objDefs[i];
        		columnTypes[i]=types[i];
        	}
        	basis = n;
        } else
        {
        	this.primaryKeyColumn =tables[0].tableName+"."+tables[0].columnNames[tables[0].idColumn];
        	String str = (ColumnNameAliases==null)?null:ColumnNameAliases.get(this.primaryKeyColumn);
            if (str!=null) this.primaryKeyColumn = str;
            for(int m=0;m<containerNo;m++)
            {
                if (m>0) 
                {
                	int dmm = m-1;
                	joinColumns[dmm]=-1;
                	String nm=joinLeftTableFields[dmm];
                	if (nm==null) throw new Exception("joinLeftTableFields parameter for view container cannot be null");
                	for(int i=0;i<basis;i++)
                	{
                        if (nm.equals(columnNames[i])) joinColumns[dmm]=i;                		
                	}
                	if (joinColumns[dmm]<0) throw new Exception("joinLeftTableFields parameter \""+nm+"\" does not match any column in previous table(s) (it must be in the form of TableName.ColumnName))");
                }
            	String[] colNames=tables[m].columnNames;
            	Object[] objDefs = tables[m].columnDefaults;
            	Class<?>[] types = tables[m].columnTypes;
            	int n=columnAmounts[m];
            	String prefix = tables[m].tableName+".";
            	for(int i=0;i<n;i++)
            	{
            		str = colNames[i];
            		String snew = (ColumnNameAliases==null)?str:ColumnNameAliases.get(str);
            		columnNames[basis+i]=prefix+(snew==null?str:snew);
            		columnDefaults[basis+i]=objDefs[i];
            		columnTypes[basis+i]=types[i];
            	}
            	basis+=n;
            }
        }
        if (hasGeneratedColumns)
        {
        	int n=columnAmounts[sourceNo-1];
        	generatedData = new AEGeneratedData[n];
        	for(int i=0;i<n;i++)
        	{
        		columnNames[basis+i]=generatedColumns[i].columnName;
        		columnDefaults[basis+i]=generatedColumns[i].defaultValue;
        		columnTypes[basis+i]=generatedColumns[i].type;
        		generatedData[i]=generatedColumns[i].generator;
        	}
        }
    }
    public void addGeneratedColumns(AEGeneratedColumn[] generatedColumns)
    {
    	super.addGeneratedColumns(generatedColumns);
        if (generatedColumns==null || generatedColumns.length==0) return;
        int addcolno = generatedColumns.length;
        if (!hasGeneratedColumns)
        {
        	hasGeneratedColumns=true;
        	sourceNo = containerNo+1;
        	int[] tmpColumnAmounts = new int[sourceNo];
        	for(int i=0;i<containerNo;i++) tmpColumnAmounts[i]=columnAmounts[i];
        	tmpColumnAmounts[containerNo]=addcolno;
            columnAmounts = tmpColumnAmounts;        	
        }
        else
        {
        	columnAmount+=addcolno;
        	columnAmounts[columnAmounts.length-1]+=addcolno;       	
        }
    }    
    @Override
    public Object clone() 
    {
            AEViewDefinition o=(AEViewDefinition)super.clone();
            o.columnAmounts = columnAmounts.clone();
            o.tables = tables.clone();
            if (joinColumns!=null)
            {
            	o.joinColumns = joinColumns.clone();
            }
            if (leftOuterJoin!=null)
            {
            	o.leftOuterJoin = leftOuterJoin.clone();
            }
            if (whereFilters!=null)
            {
            	o.whereFilters = whereFilters.clone();
            }
            if (sortColumns!=null)
            {
            	o.sortColumns = sortColumns.clone();
            }
            if (ascending!=null)
            {
            	o.ascending = ascending.clone();
            }
            if (readOnlyTables!=null)
            {
            	o.readOnlyTables = readOnlyTables.clone();
            }
            if (groupBy!=null)
            {
            	o.groupBy = groupBy.clone();
            }
            return o;
    }

}
